﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using IPC.Communication.Framework.BasicFramework;
using IPC.Communication.Framework.Core;
using IPC.Communication.Framework.Core.Address;

namespace IPC.Communication.Framework.Profinet.Fuji
{
    public class FujiSPBHelper
    {
        public static string AnalysisIntegerAddress(int address)
        {
            string text = address.ToString("D4");
            return text.Substring(2) + text.Substring(0, 2);
        }

        public static string CalculateAcc(string data)
        {
            byte[] bytes = Encoding.ASCII.GetBytes(data);
            int num = 0;
            for (int i = 0; i < bytes.Length; i++)
            {
                num += bytes[i];
            }
            return num.ToString("X4").Substring(2);
        }

        public static OperateResult<byte[]> BuildReadCommand(byte station, string address, ushort length)
        {
            station = (byte)HslHelper.ExtractParameter(ref address, "s", station);
            OperateResult<FujiSPBAddress> operateResult = FujiSPBAddress.ParseFrom(address);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult);
            }
            return BuildReadCommand(station, operateResult.Content, length);
        }

        public static OperateResult<byte[]> BuildReadCommand(byte station, FujiSPBAddress address, ushort length)
        {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.Append(':');
            stringBuilder.Append(station.ToString("X2"));
            stringBuilder.Append("09");
            stringBuilder.Append("FFFF");
            stringBuilder.Append("00");
            stringBuilder.Append("00");
            stringBuilder.Append(address.GetWordAddress());
            stringBuilder.Append(AnalysisIntegerAddress(length));
            stringBuilder.Append("\r\n");
            return OperateResult.CreateSuccessResult(Encoding.ASCII.GetBytes(stringBuilder.ToString()));
        }

        public static OperateResult<byte[]> BuildReadCommand(byte station, string[] address, ushort[] length, bool isBool)
        {
            if (address == null || length == null)
            {
                return new OperateResult<byte[]>("Parameter address or length can't be null");
            }
            if (address.Length != length.Length)
            {
                return new OperateResult<byte[]>(StringResources.Language.TwoParametersLengthIsNotSame);
            }
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.Append(':');
            stringBuilder.Append(station.ToString("X2"));
            stringBuilder.Append((6 + address.Length * 4).ToString("X2"));
            stringBuilder.Append("FFFF");
            stringBuilder.Append("00");
            stringBuilder.Append("04");
            stringBuilder.Append("00");
            stringBuilder.Append(address.Length.ToString("X2"));
            for (int i = 0; i < address.Length; i++)
            {
                station = (byte)HslHelper.ExtractParameter(ref address[i], "s", station);
                OperateResult<FujiSPBAddress> operateResult = FujiSPBAddress.ParseFrom(address[i]);
                if (!operateResult.IsSuccess)
                {
                    return OperateResult.CreateFailedResult<byte[]>(operateResult);
                }
                stringBuilder.Append(operateResult.Content.TypeCode);
                stringBuilder.Append(length[i].ToString("X2"));
                stringBuilder.Append(AnalysisIntegerAddress(operateResult.Content.AddressStart));
            }
            stringBuilder[1] = station.ToString("X2")[0];
            stringBuilder[2] = station.ToString("X2")[1];
            stringBuilder.Append("\r\n");
            return OperateResult.CreateSuccessResult(Encoding.ASCII.GetBytes(stringBuilder.ToString()));
        }

        public static OperateResult<byte[]> BuildWriteByteCommand(byte station, string address, byte[] value)
        {
            station = (byte)HslHelper.ExtractParameter(ref address, "s", station);
            OperateResult<FujiSPBAddress> operateResult = FujiSPBAddress.ParseFrom(address);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult);
            }
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.Append(':');
            stringBuilder.Append(station.ToString("X2"));
            stringBuilder.Append("00");
            stringBuilder.Append("FFFF");
            stringBuilder.Append("01");
            stringBuilder.Append("00");
            stringBuilder.Append(operateResult.Content.GetWordAddress());
            stringBuilder.Append(AnalysisIntegerAddress(value.Length / 2));
            stringBuilder.Append(value.ToHexString());
            stringBuilder[3] = ((stringBuilder.Length - 5) / 2).ToString("X2")[0];
            stringBuilder[4] = ((stringBuilder.Length - 5) / 2).ToString("X2")[1];
            stringBuilder.Append("\r\n");
            return OperateResult.CreateSuccessResult(Encoding.ASCII.GetBytes(stringBuilder.ToString()));
        }

        public static OperateResult<byte[]> BuildWriteBoolCommand(byte station, string address, bool value)
        {
            station = (byte)HslHelper.ExtractParameter(ref address, "s", station);
            OperateResult<FujiSPBAddress> operateResult = FujiSPBAddress.ParseFrom(address);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult);
            }
            if ((address.StartsWith("X") || address.StartsWith("Y") || address.StartsWith("M") || address.StartsWith("L") || address.StartsWith("TC") || address.StartsWith("CC")) && address.IndexOf('.') < 0)
            {
                operateResult.Content.BitIndex = operateResult.Content.AddressStart % 16;
                operateResult.Content.AddressStart = (ushort)(operateResult.Content.AddressStart / 16);
            }
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.Append(':');
            stringBuilder.Append(station.ToString("X2"));
            stringBuilder.Append("00");
            stringBuilder.Append("FFFF");
            stringBuilder.Append("01");
            stringBuilder.Append("02");
            stringBuilder.Append(operateResult.Content.GetWriteBoolAddress());
            stringBuilder.Append(value ? "01" : "00");
            stringBuilder[3] = ((stringBuilder.Length - 5) / 2).ToString("X2")[0];
            stringBuilder[4] = ((stringBuilder.Length - 5) / 2).ToString("X2")[1];
            stringBuilder.Append("\r\n");
            return OperateResult.CreateSuccessResult(Encoding.ASCII.GetBytes(stringBuilder.ToString()));
        }

        public static OperateResult<byte[]> CheckResponseData(byte[] content)
        {
            if (content[0] != 58)
            {
                return new OperateResult<byte[]>(content[0], "Read Faild:" + SoftBasic.ByteToHexString(content, ' '));
            }
            string @string = Encoding.ASCII.GetString(content, 9, 2);
            if (@string != "00")
            {
                return new OperateResult<byte[]>(Convert.ToInt32(@string, 16), GetErrorDescriptionFromCode(@string));
            }
            if (content[content.Length - 2] == 13 && content[content.Length - 1] == 10)
            {
                content = content.RemoveLast(2);
            }
            return OperateResult.CreateSuccessResult(content.RemoveBegin(11));
        }

        public static string GetErrorDescriptionFromCode(string code)
        {
            switch (code)
            {
                case "01":
                    return StringResources.Language.FujiSpbStatus01;
                case "02":
                    return StringResources.Language.FujiSpbStatus02;
                case "03":
                    return StringResources.Language.FujiSpbStatus03;
                case "04":
                    return StringResources.Language.FujiSpbStatus04;
                case "05":
                    return StringResources.Language.FujiSpbStatus05;
                case "06":
                    return StringResources.Language.FujiSpbStatus06;
                case "07":
                    return StringResources.Language.FujiSpbStatus07;
                case "09":
                    return StringResources.Language.FujiSpbStatus09;
                case "0C":
                    return StringResources.Language.FujiSpbStatus0C;
                default:
                    return StringResources.Language.UnknownError;
            }
        }

        public static OperateResult<byte[]> Read(IReadWriteDevice device, byte station, string address, ushort length)
        {
            OperateResult<byte[]> operateResult = BuildReadCommand(station, address, length);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult);
            }
            OperateResult<byte[]> operateResult2 = device.ReadFromCoreServer(operateResult.Content);
            if (!operateResult2.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult2);
            }
            OperateResult<byte[]> operateResult3 = CheckResponseData(operateResult2.Content);
            if (!operateResult3.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult3);
            }
            return OperateResult.CreateSuccessResult(Encoding.ASCII.GetString(operateResult3.Content.RemoveBegin(4)).ToHexBytes());
        }

        public static OperateResult Write(IReadWriteDevice device, byte station, string address, byte[] value)
        {
            OperateResult<byte[]> operateResult = BuildWriteByteCommand(station, address, value);
            if (!operateResult.IsSuccess)
            {
                return operateResult;
            }
            OperateResult<byte[]> operateResult2 = device.ReadFromCoreServer(operateResult.Content);
            if (!operateResult2.IsSuccess)
            {
                return operateResult2;
            }
            return CheckResponseData(operateResult2.Content);
        }

        public static OperateResult<bool[]> ReadBool(IReadWriteDevice device, byte station, string address, ushort length)
        {
            byte station2 = (byte)HslHelper.ExtractParameter(ref address, "s", station);
            OperateResult<FujiSPBAddress> operateResult = FujiSPBAddress.ParseFrom(address);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<bool[]>(operateResult);
            }
            if ((address.StartsWith("X") || address.StartsWith("Y") || address.StartsWith("M") || address.StartsWith("L") || address.StartsWith("TC") || address.StartsWith("CC")) && address.IndexOf('.') < 0)
            {
                operateResult.Content.BitIndex = operateResult.Content.AddressStart % 16;
                operateResult.Content.AddressStart = (ushort)(operateResult.Content.AddressStart / 16);
            }
            ushort length2 = (ushort)((operateResult.Content.GetBitIndex() + length - 1) / 16 - operateResult.Content.GetBitIndex() / 16 + 1);
            OperateResult<byte[]> operateResult2 = BuildReadCommand(station2, operateResult.Content, length2);
            if (!operateResult2.IsSuccess)
            {
                return OperateResult.CreateFailedResult<bool[]>(operateResult2);
            }
            OperateResult<byte[]> operateResult3 = device.ReadFromCoreServer(operateResult2.Content);
            if (!operateResult3.IsSuccess)
            {
                return OperateResult.CreateFailedResult<bool[]>(operateResult3);
            }
            OperateResult<byte[]> operateResult4 = CheckResponseData(operateResult3.Content);
            if (!operateResult4.IsSuccess)
            {
                return OperateResult.CreateFailedResult<bool[]>(operateResult4);
            }
            return OperateResult.CreateSuccessResult(Encoding.ASCII.GetString(operateResult4.Content.RemoveBegin(4)).ToHexBytes().ToBoolArray()
                .SelectMiddle(operateResult.Content.BitIndex, length));
        }

        public static OperateResult Write(IReadWriteDevice device, byte station, string address, bool value)
        {
            OperateResult<byte[]> operateResult = BuildWriteBoolCommand(station, address, value);
            if (!operateResult.IsSuccess)
            {
                return operateResult;
            }
            OperateResult<byte[]> operateResult2 = device.ReadFromCoreServer(operateResult.Content);
            if (!operateResult2.IsSuccess)
            {
                return operateResult2;
            }
            return CheckResponseData(operateResult2.Content);
        }

        //[AsyncStateMachine(typeof(<ReadAsync>d__13))]
        //[DebuggerStepThrough]
        //public static Task<OperateResult<byte[]>> ReadAsync(IReadWriteDevice device, byte station, string address, ushort length)
        //{
        //    <ReadAsync>d__13 stateMachine = new <ReadAsync>d__13();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<byte[]>>.Create();
        //    stateMachine.device = device;
        //    stateMachine.station = station;
        //    stateMachine.address = address;
        //    stateMachine.length = length;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<WriteAsync>d__14))]
        //[DebuggerStepThrough]
        //public static Task<OperateResult> WriteAsync(IReadWriteDevice device, byte station, string address, byte[] value)
        //{
        //    <WriteAsync>d__14 stateMachine = new <WriteAsync>d__14();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.device = device;
        //    stateMachine.station = station;
        //    stateMachine.address = address;
        //    stateMachine.value = value;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<ReadBoolAsync>d__15))]
        //[DebuggerStepThrough]
        //public static Task<OperateResult<bool[]>> ReadBoolAsync(IReadWriteDevice device, byte station, string address, ushort length)
        //{
        //    <ReadBoolAsync>d__15 stateMachine = new <ReadBoolAsync>d__15();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<bool[]>>.Create();
        //    stateMachine.device = device;
        //    stateMachine.station = station;
        //    stateMachine.address = address;
        //    stateMachine.length = length;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<WriteAsync>d__16))]
        //[DebuggerStepThrough]
        //public static Task<OperateResult> WriteAsync(IReadWriteDevice device, byte station, string address, bool value)
        //{
        //    <WriteAsync>d__16 stateMachine = new <WriteAsync>d__16();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.device = device;
        //    stateMachine.station = station;
        //    stateMachine.address = address;
        //    stateMachine.value = value;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}
    }
}